import socket
import threading
import time

from common.logger_factory import Log

# 心跳间隔时间（秒）
HEARTBEAT_INTERVAL = 5


class HeartbeatClient:
    """
    心跳客户端，集成到业务服务中；用于服务器的健康检测
    """

    """
    重试间隔时间（秒）
    """
    __retry_interval = 5

    def __init__(self, host, port, client_port=None):
        self.host = host
        self.port = port
        self.client_port = client_port
        self.client_socket = None
        self.connected = False
        self.lock = threading.Lock()
        self.heartbeat_thread = None
        self.running = False

    def start(self):
        self.running = True
        threading.Thread(target=self.connect_with_retry, daemon=True).start()

    def stop(self):
        self.running = False
        with self.lock:
            if self.client_socket:
                self.client_socket.close()
                self.client_socket = None
            self.connected = False

    def connect_with_retry(self):
        while self.running:
            try:
                self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                # 绑定客户端端口（如果指定了的话）
                if self.client_port is not None:
                    self.client_socket.bind(('', self.client_port))
                self.client_socket.connect((self.host, self.port))
                Log.console().info(f"连接到心跳服务中心 {self.host}:{self.port}")
                with self.lock:
                    self.connected = True
                self.heartbeat_thread = threading.Thread(target=self.send_heartbeats, daemon=True)
                self.heartbeat_thread.start()
                break
            except (socket.error, ConnectionRefusedError) as e:
                Log.console().warning(f"连接到心跳服务中心失败：{e}，将在 {self.__retry_interval} 秒后重试")
                time.sleep(self.__retry_interval)

    def send_heartbeats(self):
        while self.running:
            time.sleep(HEARTBEAT_INTERVAL)
            with self.lock:
                if not self.connected:
                    break
            try:
                self.client_socket.send(b'heartbeat')
            except socket.error:
                Log.console().warning("心跳发送失败！")
                with self.lock:
                    self.connected = False
                self.connect_with_retry()
                break
